package com.eshop.config;

import com.eshop.modules.system.domain.Dept;
import com.eshop.modules.system.service.DeptService;
import com.eshop.modules.system.service.RoleService;
import com.eshop.modules.system.service.UserService;
import com.eshop.modules.system.service.dto.RoleSmallDto;
import com.eshop.modules.system.service.dto.UserDto;
import com.eshop.utils.SecurityUtils;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 用于根据角色的数据范围权限获取用户所能访问的部门ID集合。
 * 组件中注入了 UserService、RoleService 和 DeptService 三个服务，
 * 分别用于获取用户信息、角色信息和部门信息
 */
@Component
public class DataScope {
    private final String[] scopeType;
    private final UserService userService;
    private final RoleService roleService;
    private final DeptService deptService;

    public DataScope(final UserService userService, final RoleService roleService, final DeptService deptService) {
        this.scopeType = new String[]{"全部", "本级", "自定义"};
        this.userService = userService;
        this.roleService = roleService;
        this.deptService = deptService;
    }

    /**
     * 方法首先获取当前登录用户的详细信息，然后遍历用户关联的所有角色。针对不同角色的数据范围类型，执行不同的操作
     * 若角色数据范围为"全部"，则返回空集合，表示用户可以访问所有部门。
     * 若角色数据范围为"本级"，则将用户所在部门的ID添加到集合中。
     * 若角色数据范围为"自定义"，则查找与该角色关联的所有部门，并递归收集这些部门及其子部门的ID加入到集合中。
     */
    public Set<Long> getDeptIds() {
        final UserDto user = this.userService.findByName(SecurityUtils.getUsername());
        final Set<Long> deptIds = new HashSet<Long>();
        final List<RoleSmallDto> roleSet = this.roleService.findByUsersId(user.getId());
        for (final RoleSmallDto role : roleSet) {
            if (this.scopeType[0].equals(role.getDataScope())) {
                return new HashSet<Long>();
            }
            if (this.scopeType[1].equals(role.getDataScope())) {
                deptIds.add(user.getDept().getId());
            }
            if (!this.scopeType[2].equals(role.getDataScope())) {
                continue;
            }
            final Set<Dept> depts = this.deptService.findByRoleIds(role.getId());
            for (final Dept dept : depts) {
                deptIds.add(dept.getId());
                final List<Dept> deptChildren = this.deptService.findByPid(dept.getId());
                if (deptChildren != null && deptChildren.size() != 0) {
                    deptIds.addAll(this.getDeptChildren(deptChildren));
                }
            }
        }
        return deptIds;
    }

    /**
     * 辅助方法，它接收一个部门列表，递归遍历并收集所有子部门的ID，
     * 返回一个包含所有子部门ID的列表。在遍历过程中，仅处理启用状态的部门（enabled为true）
     */
    public List<Long> getDeptChildren(List<Dept> deptList) {
        List<Long> list = new ArrayList();
        deptList.forEach((dept) -> {
            if (dept != null && dept.getEnabled()) {
                List<Dept> depts = this.deptService.findByPid(dept.getId());
                if (deptList.size() != 0) {
                    list.addAll(this.getDeptChildren(depts));
                }

                list.add(dept.getId());
            }

        });
        return list;
    }
}
